home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Games / xmine / xmine.c < prev    next >
C/C++ Source or Header  |  1995-05-03  |  38KB  |  1,488 lines

  1. /* xmine - Copyright (c) 1993 by Paul Falstad
  2.  * freely redistributable
  3.  */
  4.  
  5. #include <stdio.h>
  6. #include <Xm/MainW.h>
  7. #include <Xm/DrawingA.h>
  8. #include <Xm/PushBG.h>
  9. #include <Xm/PushB.h>
  10. #include <Xm/RowColumn.h>
  11. #include <Xm/ScrolledW.h>
  12. #include <Xm/Form.h>
  13. #include <Xm/CascadeBG.h>
  14. #include <Xm/Separator.h>
  15. #include <Xm/ToggleB.h>
  16. #include <Xm/DialogS.h>
  17. #include <Xm/TextF.h>
  18. #include <Xm/LabelG.h>
  19. #include <Xm/PanedW.h>
  20.  
  21. #include "patchlevel.h"
  22.  
  23. #define GSPACEX 16
  24. #define GSPACEY 16
  25.  
  26. #define SCORE_FILE "~/.xmine_scores"
  27. #define TOPMARGIN 60
  28. #define BOTMARGIN 12
  29. #define SIDEMARGIN 12
  30. #define STATUS_Y_OFFSET 12
  31. #define TOTAL_WIDTH (SIDEMARGIN*2+gsizex*GSPACEX)
  32. #define TOTAL_HEIGHT (TOPMARGIN+BOTMARGIN+gsizey*GSPACEY)
  33. #define STATUS_HEIGHT (TOPMARGIN-STATUS_Y_OFFSET*2)
  34. #define DIGIT_X_OFFSET (SIDEMARGIN+4)
  35. #define DIGIT_Y_OFFSET (STATUS_Y_OFFSET+4)
  36. #define DIGIT_HEIGHT (TOPMARGIN-DIGIT_Y_OFFSET*2)
  37. #define DIGIT_WIDTH 16
  38. #define DIGIT_COUNT 3
  39. #define DIGIT_MARGIN 2
  40. #define DIGIT_HWEDGE_WIDTH (DIGIT_WIDTH-(DIGIT_MARGIN+1)*2)
  41. #define DIGIT_VWEDGE_HEIGHT ((DIGIT_HEIGHT-7)/2)
  42.  
  43. #define COVERED 0
  44. #define MARKED 1
  45. #define UNCOVERED 2
  46. #define QUESTIONED 3
  47. #define MINE -1
  48. #define MAX_GSIZEX 100
  49. #define MAX_GSIZEY 100
  50. int grid[MAX_GSIZEX][MAX_GSIZEY]; /* fix this */
  51. int gridview[MAX_GSIZEX][MAX_GSIZEY]; /* fix this */
  52. #define INITIAL_SIZE_X 8
  53. #define INITIAL_SIZE_Y 8
  54. int gsizex = INITIAL_SIZE_X, gsizey = INITIAL_SIZE_Y;
  55. int layed_out = 0, game_on = 1, face_armed = 0;
  56. int questions_allowed = 0, game_level = 0;
  57. XFontStruct *font_info;
  58. Widget drawarea;
  59. Display *disp;
  60. Window win;
  61.  
  62. #define COL_BLUE 0
  63. #define COL_LIMEGREEN 1
  64. #define COL_RED 2
  65. #define COL_NAVY 3
  66. #define COL_BROWN 4
  67. #define COL_AQUA 5
  68. #define COL_BLACK 6
  69. #define COL_GRAY 7
  70. #define COL_WHITE 8
  71. #define COL_LITEGRAY 9
  72. #define COL_DARKGRAY 10
  73. #define COL_YELLOW 11
  74. #define COL_DARKRED 12
  75. #define COL_COUNT 13
  76. char *colnames[COL_COUNT] = {
  77.     "Blue", "LimeGreen", "Red", "Navy",
  78.     "Brown", "MediumAquamarine", "Black", "Gray",
  79.     "White", "Grey75", "Grey50", "Yellow", "darkred"
  80. };
  81. XColor cols[COL_COUNT];
  82.  
  83. int numcols[] = {
  84.     COL_BLUE, COL_LIMEGREEN, COL_RED, COL_NAVY,
  85.     COL_BROWN, COL_AQUA, COL_BLACK, COL_GRAY
  86. };
  87.  
  88. #include "cool.xbm"
  89. #include "fillface.xbm"
  90. #include "dead.xbm"
  91. #include "happy.xbm"
  92. #include "ohno.xbm"
  93. #include "press.xbm"
  94.  
  95. #define FACE_HAPPY 0
  96. #define FACE_OHNO 1
  97. #define FACE_COOL 2
  98. #define FACE_DEAD 3
  99. #define FACE_PRESS 4
  100. #define FACE_COUNT 5
  101. Pixmap faces[FACE_COUNT];
  102. static char *face_bits[FACE_COUNT] = {
  103.     happy_bits, ohno_bits, cool_bits, dead_bits, press_bits
  104. };
  105. int cur_face = FACE_HAPPY;
  106. int mine_count, covered_count, marked_count;
  107. int armed_x, armed_y, armed, timer;
  108. XtIntervalId timer_id;
  109.  
  110. #define FACE_BUTTON_WIDTH (fillface_width+5)
  111. #define FACE_BUTTON_HEIGHT (fillface_height+5)
  112. #define FACE_X_POS ((TOTAL_WIDTH-FACE_BUTTON_WIDTH)/2+1)
  113. #define FACE_Y_POS ((TOPMARGIN-FACE_BUTTON_HEIGHT)/2)
  114.  
  115. GC gc;
  116.  
  117. #ifdef __STDC__
  118. #define P(X) X
  119. #else
  120. #define P(X) ()
  121. #endif /* __STDC__ */
  122.  
  123. typedef void (*void_proc)();
  124.  
  125. extern void search_action P ((Widget, XButtonEvent *, String *, int *));
  126. extern void clear_action P ((Widget, XButtonEvent *, String *, int *));
  127. extern void mark_action P ((Widget, XButtonEvent *, String *, int *));
  128. extern void redraw_cb P ((Widget, XtPointer, XmDrawingAreaCallbackStruct *));
  129. extern void redrawsquare P ((int, int));
  130. extern void drawsquare P ((int, int));
  131. extern int hasmine P ((int, int));
  132. extern void uncover P ((int, int));
  133. extern void clear_around P ((int, int));
  134. extern int is_state P ((int, int, int));
  135. extern void shadow_rev_rect P ((int, int, int, int, int));
  136. extern void shadow_rect P ((int, int, int, int, int));
  137. extern XmString genxmstr P ((char *));
  138. extern void layout_board P ((int, int));
  139. extern void boom P ((void));
  140. extern void restart P ((void));
  141. extern void draw_face P ((void));
  142. extern void set_face P ((int));
  143. extern void winner P ((void));
  144. extern void draw_blank_square P ((int, int, int));
  145. extern void draw_button P ((int, int));
  146. extern void arm_clear P ((int, int, int));
  147. extern void track_face P ((int, int, int));
  148. extern void arm_face P ((int));
  149. extern void draw_digit P ((int, int, int));
  150. extern void draw_digits P ((int, int));
  151. extern void timer_callback P ((void));
  152. extern void set_level P ((Widget, int));
  153. extern void tog_question P ((void));
  154. extern void set_custom P ((void));
  155. extern void dialog_ok P ((void));
  156. extern void get_text_int P ((Widget, int *));
  157. extern void best_times P ((void));
  158. extern void about P ((void));
  159. extern struct scores *get_scores P ((void));
  160. extern void write_scores P ((struct scores *));
  161. extern void get_score_file_name P ((char *));
  162. extern void new_best P ((int));
  163. extern void clear_scores P ((void));
  164. extern int cant_write_score_file P ((void));
  165. extern void fix_size P ((void));
  166. extern void relax_size P ((void));
  167. extern void resize_handler P ((Widget, XtPointer, XEvent *, Boolean *));
  168.  
  169. Pixmap fillface;
  170. XtAppContext app;
  171. Widget toplevel, menubar;
  172. Widget level_buttons[4];
  173.  
  174. struct scores {
  175.     char names[3][80];
  176.     int times[3];
  177. };
  178.  
  179. char *fallbacks[] = {
  180. #include "fallback.h"
  181.     NULL
  182. };
  183.  
  184. main(argc, argv)
  185. unsigned int argc;
  186. char *argv[];
  187. {
  188.     Widget main_w, drawing_a, menu, btn;
  189.     XGCValues gcv;
  190.     void draw(), redraw_cb(), set_color(), exit();
  191.     XColor unused;
  192.     int i;
  193.  
  194.     XtActionsRec actions[3];
  195.     String translations =
  196.         "<Btn1Down>:   search(down)\n\
  197.          <Btn1Up>:     search(up)\n\
  198.          <Btn1Motion>: search(move)\n\
  199.      <Btn2Down>:   clear(down)\n\
  200.      <Btn2Motion>: clear(move)\n\
  201.      <Btn2Up>:     clear(up)\n\
  202.      <Btn3Down>:   mark(down)\n";
  203.  
  204.     toplevel = XtVaAppInitialize(&app, "Xmine", NULL, 0,
  205.         &argc, argv, fallbacks, NULL);
  206.  
  207.     main_w = XtVaCreateManagedWidget("main_w",
  208.         xmFormWidgetClass, toplevel,
  209.     NULL);
  210.  
  211.     menubar = XmCreateMenuBar(main_w, "menubar", NULL, 0);
  212.     XtVaSetValues(menubar,
  213.     XmNtopAttachment, XmATTACH_FORM,
  214.     XmNleftAttachment, XmATTACH_FORM,
  215.     XmNrightAttachment,    XmATTACH_FORM,
  216.     NULL);
  217.     menu = XmCreatePulldownMenu(menubar, "game_menu", NULL, 0);
  218.     XtVaCreateManagedWidget("game",
  219.     xmCascadeButtonGadgetClass, menubar,
  220.     XmNsubMenuId,            menu,
  221.     XmNbackground,     cols[COL_LITEGRAY].pixel,
  222.     NULL);
  223.     btn = XtVaCreateManagedWidget("New",
  224.     xmPushButtonGadgetClass,   menu,
  225.     NULL);
  226.     XtAddCallback(btn, XmNactivateCallback, (void_proc) restart, 0);
  227.     XtVaCreateManagedWidget("_sep1", xmSeparatorWidgetClass, menu, NULL);
  228.     level_buttons[0] = btn = XtVaCreateManagedWidget("Beginner",
  229.     xmToggleButtonWidgetClass,   menu,
  230.     NULL);
  231.     XtAddCallback(btn, XmNvalueChangedCallback, (void_proc) set_level,
  232. (XtPointer) 1);
  233.     level_buttons[1] = btn = XtVaCreateManagedWidget("Intermediate",
  234.     xmToggleButtonWidgetClass,   menu,
  235.     NULL);
  236.     XtAddCallback(btn, XmNvalueChangedCallback, (void_proc) set_level,
  237. (XtPointer) 2);
  238.     level_buttons[2] = btn = XtVaCreateManagedWidget("Expert",
  239.     xmToggleButtonWidgetClass,   menu,
  240.     NULL);
  241.     XtAddCallback(btn, XmNvalueChangedCallback, (void_proc) set_level,
  242. (XtPointer) 3);
  243.     level_buttons[3] = btn = XtVaCreateManagedWidget("Custom",
  244.     xmToggleButtonWidgetClass,   menu,
  245.     NULL);
  246.     XtAddCallback(btn, XmNvalueChangedCallback, (void_proc) set_custom, NULL);
  247.     XtVaCreateManagedWidget("_sep2", xmSeparatorWidgetClass, menu, NULL);
  248.     btn = XtVaCreateManagedWidget("Marks",
  249.     xmToggleButtonWidgetClass,   menu,
  250.     NULL);
  251.     XtAddCallback(btn, XmNvalueChangedCallback,
  252.     (XtPointer) tog_question, NULL);
  253.     XtVaCreateManagedWidget("_sep3", xmSeparatorWidgetClass, menu, NULL);
  254.     btn = XtVaCreateManagedWidget("Best",
  255.     xmPushButtonWidgetClass,   menu,
  256.     NULL);
  257.     XtAddCallback(btn, XmNactivateCallback, (void_proc) best_times, NULL);
  258.     btn = XtVaCreateManagedWidget("About",
  259.     xmPushButtonWidgetClass,   menu,
  260.     NULL);
  261.     XtAddCallback(btn, XmNactivateCallback, (void_proc) about, NULL);
  262.     btn = XtVaCreateManagedWidget("Exit",
  263.     xmPushButtonWidgetClass,   menu,
  264.     NULL);
  265.     XtAddCallback(btn, XmNactivateCallback, (void_proc) exit, NULL);
  266.     XtManageChild(menubar);
  267.  
  268.     for (i = 0; i != COL_COUNT; i++)
  269.     XAllocNamedColor(XtDisplay(main_w),
  270.         DefaultColormapOfScreen(XtScreen(main_w)),
  271.         colnames[i], &cols[i], &unused);
  272.     {
  273.     cols[COL_DARKRED].red = 60*256;
  274.     cols[COL_DARKRED].green = cols[COL_DARKRED].blue = 0;
  275.     XAllocColor(XtDisplay(main_w),
  276.         DefaultColormapOfScreen(XtScreen(main_w)),
  277.         &cols[COL_DARKRED]);
  278.     }
  279.  
  280.     gcv.foreground = cols[COL_WHITE].pixel;
  281.     gc = XCreateGC(XtDisplay(main_w),
  282.         RootWindowOfScreen(XtScreen(main_w)), GCForeground, &gcv);
  283.  
  284.     actions[0].string = "clear";
  285.     actions[0].proc = (void_proc) clear_action;
  286.     actions[1].string = "search";
  287.     actions[1].proc = (void_proc) search_action;
  288.     actions[2].string = "mark";
  289.     actions[2].proc = (void_proc) mark_action;
  290.     XtAppAddActions(app, actions, 3);
  291.  
  292.     drawing_a = XtVaCreateManagedWidget("drawing_a",
  293.         xmDrawingAreaWidgetClass, main_w,
  294.         XmNtranslations, XtParseTranslationTable(translations),
  295.         XmNwidth,        GSPACEX*gsizex+SIDEMARGIN*2,
  296.         XmNheight,       GSPACEY*gsizey+TOPMARGIN+BOTMARGIN,
  297.         XmNresizePolicy, XmNONE,  /* remain this a fixed size */
  298.     XmNbackground,     cols[COL_LITEGRAY].pixel,
  299.     XmNtopAttachment,XmATTACH_WIDGET,
  300.     XmNtopWidget,     menubar,
  301.     XmNleftAttachment,XmATTACH_FORM,
  302.     XmNrightAttachment,XmATTACH_FORM,
  303.     XmNbottomAttachment,XmATTACH_FORM,
  304.         NULL);
  305.     XtAddCallback(drawing_a, XmNexposeCallback, (void_proc) redraw_cb, NULL);
  306.     font_info = XLoadQueryFont(XtDisplay(main_w),
  307.     "-*-courier-bold-r-normal-*-*-120-*");
  308.     XSetFont(XtDisplay(main_w), gc, font_info->fid);
  309.  
  310.     set_level((Widget) 0, 1);
  311.     XtAddEventHandler(drawing_a,
  312.     StructureNotifyMask, False, resize_handler, 0);
  313.     XtRealizeWidget(toplevel);
  314.     fillface = XCreateBitmapFromData(XtDisplay(main_w),
  315.     XtWindow(main_w), fillface_bits,
  316.     fillface_width, fillface_height);
  317.     for (i = 0; i != FACE_COUNT; i++)
  318.     faces[i] = XCreateBitmapFromData(XtDisplay(main_w),
  319.         XtWindow(main_w), face_bits[i],
  320.         fillface_width, fillface_height);
  321.     drawarea = drawing_a;
  322.     win = XtWindow(drawing_a);
  323.     disp = XtDisplay(drawing_a);
  324.     XtAppMainLoop(app);
  325.     return 0;
  326. }
  327.  
  328. void
  329. search_action(widget, event, args, num_args)
  330. Widget widget;
  331. XButtonEvent *event;
  332. String *args;
  333. int *num_args;
  334. {
  335.     int xg, yg;
  336.  
  337.     track_face(event->x, event->y, *args[0]);
  338.     if (!game_on) return;
  339.     xg = (event->x-SIDEMARGIN)/GSPACEX;
  340.     yg = (event->y-TOPMARGIN)/GSPACEY;
  341.     if (!strcmp(args[0], "down")) {
  342.     armed = False;
  343.     if (!(xg >= 0 && xg < gsizex && yg >= 0 && yg < gsizey))
  344.         return;
  345.     if (gridview[xg][yg] != COVERED) return;
  346.     armed_x = xg; armed_y = yg;
  347.     armed = True;
  348.     set_face(FACE_OHNO);
  349.     draw_blank_square(xg, yg, True);
  350.     return;
  351.     }
  352.     if (!strcmp(args[0], "move")) {
  353.     if (xg == armed_x && yg == armed_y) {
  354.         if (!armed) {
  355.         set_face(FACE_OHNO);
  356.         draw_blank_square(armed_x, armed_y, True);
  357.         armed = True;
  358.         }
  359.     } else {
  360.         if (armed) {
  361.         set_face(FACE_HAPPY);
  362.         draw_button(armed_x, armed_y);
  363.         armed = False;
  364.         }
  365.     }
  366.     return;
  367.     }
  368.     if (!armed) return;
  369.     if (!layed_out) layout_board(armed_x, armed_y);
  370.     uncover(armed_x, armed_y);
  371.     if (game_on) set_face(FACE_HAPPY);
  372. }
  373.  
  374. void
  375. track_face(x, y, op)
  376. int x, y, op;
  377. {
  378.     int onface = False;
  379.  
  380.     if (x >= FACE_X_POS && x <= FACE_X_POS+FACE_BUTTON_WIDTH &&
  381.     y >= FACE_Y_POS && y <= FACE_Y_POS+FACE_BUTTON_HEIGHT)
  382.     onface = True;
  383.     if (op == 'u') {
  384.     if (!face_armed) return;
  385.     arm_face(False);
  386.     restart();
  387.     return;
  388.     }
  389.     if (op == 'd') {
  390.     if (!onface) return;
  391.     arm_face(True);
  392.     armed = False;
  393.     return;
  394.     }
  395.     if (onface != face_armed)
  396.     arm_face(onface);
  397. }
  398.  
  399. void
  400. arm_face(armit)
  401. int armit;
  402. {
  403.     face_armed = armit;
  404.     XClearArea(disp, win,
  405.     FACE_X_POS, FACE_Y_POS, FACE_BUTTON_WIDTH, FACE_BUTTON_HEIGHT,
  406.     False);
  407.     if (face_armed)
  408.     shadow_rev_rect(FACE_X_POS+2, FACE_Y_POS+2,
  409.         FACE_BUTTON_WIDTH-4, FACE_BUTTON_HEIGHT-4, 2);
  410.     else
  411.     shadow_rect(FACE_X_POS, FACE_Y_POS,
  412.         FACE_BUTTON_WIDTH, FACE_BUTTON_HEIGHT, 2);
  413.     draw_face();
  414. }
  415.  
  416. void
  417. mark_action(widget, event, args, num_args)
  418. Widget widget;
  419. XButtonEvent *event;
  420. String *args;
  421. int *num_args;
  422. {
  423.     if (!game_on) return;
  424.     if (!layed_out) return;
  425.     if (!strcmp(args[0], "down")) {
  426.     int xg, yg;
  427.  
  428.     xg = (event->x-SIDEMARGIN)/GSPACEX;
  429.     yg = (event->y-TOPMARGIN)/GSPACEY;
  430.     if (xg >= 0 && xg < gsizex &&
  431.         yg >= 0 && yg < gsizey) {
  432.         if (gridview[xg][yg] == UNCOVERED) return;
  433.         if (gridview[xg][yg] == MARKED) {
  434.         gridview[xg][yg] = (questions_allowed) ? QUESTIONED : COVERED;
  435.         marked_count--;
  436.         } else if (gridview[xg][yg] == QUESTIONED)
  437.         gridview[xg][yg] = COVERED;
  438.         else {
  439.         gridview[xg][yg] = MARKED;
  440.         marked_count++;
  441.         }
  442.         redrawsquare(xg, yg);
  443.         draw_digits(mine_count-marked_count, 0);
  444.         draw_digits(timer, 1);
  445.     }
  446.     }
  447. }
  448.  
  449. void
  450. clear_action(widget, event, args, num_args)
  451. Widget widget;
  452. XButtonEvent *event;
  453. String *args;
  454. int *num_args;
  455. {
  456.     int xg, yg;
  457.  
  458.     if (!game_on) return;
  459.     if (!layed_out) return;
  460.     xg = (event->x-SIDEMARGIN)/GSPACEX;
  461.     yg = (event->y-TOPMARGIN)/GSPACEY;
  462.     if (!(xg >= 0 && xg < gsizex && yg >= 0 && yg < gsizey))
  463.     return;
  464.     if (!strcmp(args[0], "down")) {
  465.     arm_clear(xg, yg, True);
  466.     armed_x = xg; armed_y = yg;
  467.     return;
  468.     }
  469.     if (!strcmp(args[0], "move")) {
  470.     int arm_it = (xg == armed_x && yg == armed_y);
  471.     if (arm_it != armed) arm_clear(armed_x, armed_y, arm_it);
  472.     return;
  473.     }
  474.     if (!armed) return;
  475.     arm_clear(armed_x, armed_y, False);
  476.     clear_around(xg, yg);
  477.     if (game_on)
  478.     set_face(FACE_HAPPY);
  479. }
  480.  
  481. void
  482. arm_clear(x, y, armit)
  483. int x, y, armit;
  484. {
  485.     int dx, dy;
  486.  
  487.     armed = armit;
  488.     set_face(armit ? FACE_OHNO : FACE_HAPPY);
  489.     for (dx = -1; dx <= 1; dx++)
  490.     for (dy = -1; dy <= 1; dy++)
  491.         if (is_state(x+dx, y+dy, COVERED))
  492.         if (armit)
  493.             draw_blank_square(x+dx, y+dy, True);
  494.         else
  495.             draw_button(x+dx, y+dy);
  496. }
  497.  
  498. void
  499. draw_face()
  500. {
  501.     int x, y;
  502.  
  503.     x = (TOTAL_WIDTH-fillface_width)/2+face_armed;
  504.     y = (TOPMARGIN-fillface_height)/2+face_armed;
  505.     XSetClipMask(disp, gc, fillface);
  506.     XSetClipOrigin(disp, gc, x, y);
  507.     XSetBackground(disp, gc, cols[COL_YELLOW].pixel);
  508.     XSetForeground(disp, gc, cols[COL_BLACK].pixel);
  509.     XCopyPlane(disp,
  510.     (Drawable) faces[(face_armed) ? FACE_PRESS : cur_face],
  511.     win, gc, 0, 0,
  512.     fillface_width, fillface_height, x, y, 1L);
  513.     XSetClipMask(disp, gc, None);
  514. }
  515.  
  516. void
  517. set_face(f)
  518. int f;
  519. {
  520.     if (cur_face == f) return;
  521.     cur_face = f;
  522.     draw_face();
  523. }
  524.  
  525. void
  526. redraw_cb(drawing_a, client_data, cbs)
  527. Widget    drawing_a;
  528. XtPointer client_data;
  529. XmDrawingAreaCallbackStruct *cbs;
  530. {
  531.     int x, y, w, h, xf, yf, xt, yt;
  532.  
  533.     x = cbs->event->xexpose.x-SIDEMARGIN;
  534.     y = cbs->event->xexpose.y-TOPMARGIN;
  535.     w = cbs->event->xexpose.width;
  536.     h = cbs->event->xexpose.height;
  537.     xf = x/GSPACEX;
  538.     yf = y/GSPACEY;
  539.     xt = (x+w+GSPACEX-1)/GSPACEX;
  540.     yt = (y+h+GSPACEX-1)/GSPACEX;
  541.     for (x = xf; x <= xt; x++)
  542.     for (y = yf; y <= yt; y++)
  543.         drawsquare(x, y);
  544.     if (xf < 0 || yf < 0 || xt >= gsizex || yt >= gsizey) {
  545.     shadow_rect(0, 0, TOTAL_WIDTH, TOTAL_HEIGHT, 3);
  546.     shadow_rev_rect(SIDEMARGIN, TOPMARGIN,
  547.         TOTAL_WIDTH-SIDEMARGIN*2,
  548.         TOTAL_HEIGHT-(TOPMARGIN+BOTMARGIN), 3);
  549.     shadow_rev_rect(SIDEMARGIN, STATUS_Y_OFFSET,
  550.         TOTAL_WIDTH-SIDEMARGIN*2,
  551.         STATUS_HEIGHT, 3);
  552.     shadow_rect(FACE_X_POS, FACE_Y_POS,
  553.         FACE_BUTTON_WIDTH, FACE_BUTTON_HEIGHT, 2);
  554.     draw_face();
  555.     draw_digits(mine_count-marked_count, 0);
  556.     draw_digits(timer, 1);
  557.     }
  558. }
  559.  
  560. void
  561. redrawsquare(x, y)
  562. int x, y;
  563. {
  564.     XClearArea(disp, win, x*GSPACEX+SIDEMARGIN,
  565.     y*GSPACEY+TOPMARGIN, GSPACEX, GSPACEY, True);
  566. }
  567.  
  568. void
  569. redraw_all()
  570. {
  571.     XClearArea(disp, win, SIDEMARGIN,
  572.     TOPMARGIN, GSPACEX*gsizex, GSPACEY*gsizey, True);
  573. }
  574.  
  575. void
  576. redraw_entire()
  577. {
  578.     if (disp)
  579.     XClearArea(disp, win, 0, 0, TOTAL_WIDTH, TOTAL_HEIGHT, True);
  580. }
  581.  
  582. void
  583. shadow_rect(xp, yp, w, h, thick)
  584. int xp, yp, w, h, thick;
  585. {
  586.     int off = 0;
  587.  
  588.     w--, h--;
  589.     while (thick--) {
  590.     XSetForeground(disp, gc, cols[COL_WHITE].pixel);
  591.     XDrawLine(disp, win, gc,
  592.         xp, yp+off, xp+w-off, yp+off);
  593.     XDrawLine(disp, win, gc,
  594.         xp+off, yp, xp+off, yp+h-off);
  595.     XSetForeground(disp, gc, cols[COL_DARKGRAY].pixel);
  596.     XDrawLine(disp, win, gc,
  597.         xp+off, yp+h-off, xp+w, yp+h-off);
  598.     XDrawLine(disp, win, gc,
  599.         xp+w-off, yp+off, xp+w-off, yp+h);
  600.     off++;
  601.     }
  602. }
  603.  
  604. void
  605. shadow_rev_rect(xp, yp, w, h, thick)
  606. int xp, yp, w, h, thick;
  607. {
  608.     int off = 0;
  609.  
  610.     w--, h--;
  611.     xp -= thick; yp -= thick;
  612.     w += thick*2; h += thick*2;
  613.     while (thick--) {
  614.     XSetForeground(disp, gc, cols[COL_DARKGRAY].pixel);
  615.     XDrawLine(disp, win, gc,
  616.         xp, yp+off, xp+w-off, yp+off);
  617.     XDrawLine(disp, win, gc,
  618.         xp+off, yp, xp+off, yp+h-off);
  619.     XSetForeground(disp, gc, cols[COL_WHITE].pixel);
  620.     XDrawLine(disp, win, gc,
  621.         xp+off, yp+h-off, xp+w, yp+h-off);
  622.     XDrawLine(disp, win, gc,
  623.         xp+w-off, yp+off, xp+w-off, yp+h);
  624.     off++;
  625.     }
  626. }
  627.  
  628. void
  629. draw_button(xp, yp)
  630. int xp, yp;
  631. {
  632.     xp = xp*GSPACEX+SIDEMARGIN;
  633.     yp = yp*GSPACEY+TOPMARGIN;
  634.     shadow_rect(xp, yp, GSPACEX, GSPACEY, 2);
  635. }
  636.  
  637. void
  638. draw_blank_square(xp, yp, clr)
  639. int xp, yp, clr;
  640. {
  641.     xp = xp*GSPACEX+SIDEMARGIN;
  642.     yp = yp*GSPACEY+TOPMARGIN;
  643.     if (clr)
  644.     XClearArea(disp, win,
  645.         xp, yp, GSPACEX, GSPACEY, False);
  646.     XSetForeground(disp, gc, cols[COL_DARKGRAY].pixel);
  647.     XDrawLine(disp, win, gc,
  648.     xp, yp, xp+GSPACEX-1, yp);
  649.     XDrawLine(disp, win, gc,
  650.     xp, yp, xp, yp+GSPACEY-1);
  651. }
  652.  
  653. void
  654. drawsquare(x, y)
  655. int x, y;
  656. {
  657.     int xp, yp;
  658.     char buf[2];
  659.     int wid;
  660.     int color, yoffset = 0;
  661.  
  662.     if (x < 0 || y < 0 || x >= gsizex || y >= gsizey) return;
  663.     buf[1] = 0;
  664.     xp = x*GSPACEX+SIDEMARGIN;
  665.     yp = y*GSPACEY+TOPMARGIN;
  666.     if (gridview[x][y] == UNCOVERED) {
  667.     draw_blank_square(x, y, False);
  668.     if (!grid[x][y]) return;
  669.     if (grid[x][y] == MINE) {
  670.         buf[0] = 'M';
  671.         color = COL_BLACK;
  672.     } else {
  673.         color = numcols[grid[x][y]-1];
  674.         buf[0] = grid[x][y]+'0';
  675.         yoffset = 2;
  676.     }
  677.     } else if (gridview[x][y] == MARKED) {
  678.     draw_button(x, y);
  679.     buf[0] = 'X';
  680.     color = COL_RED;
  681.     } else if (gridview[x][y] == QUESTIONED) {
  682.     draw_button(x, y);
  683.     buf[0] = '?';
  684.     color = COL_RED;
  685.     } else {
  686.     draw_button(x, y);
  687.     return;
  688.     }
  689.  
  690.     wid = XTextWidth(font_info, buf, 1);
  691.     XSetForeground(disp, gc, cols[color].pixel);
  692.     XDrawString(disp, win, gc,
  693.     xp+(GSPACEX-wid)/2,
  694.     yp+(GSPACEY+font_info->ascent-font_info->descent)/2+yoffset,
  695.     buf, 1);
  696. }
  697.  
  698. void
  699. layout_board(fx, fy)
  700. int fx, fy;
  701. {
  702.     int i, x, y, xd, yd, tries;
  703.  
  704.     srand((unsigned int) time(0));
  705.     for (i = 0; i != mine_count; i++) {
  706.     tries = 1000;
  707.     do {
  708.         x = (rand()>>1) % gsizex;
  709.         y = (rand()>>1) % gsizey;
  710.         tries--;
  711.     } while (tries && (grid[x][y] ||
  712.              !(x < fx-1 || x > fx+1 || y < fy-1 || y > fy+1)));
  713.     grid[x][y] = MINE;
  714.     if (!tries) {
  715.         mine_count = i;
  716.         break;
  717.     }
  718.     }
  719.     for (x = 0; x != gsizex; x++)
  720.     for (y = 0; y != gsizey; y++) {
  721.         if (grid[x][y] == MINE) continue;
  722.         i = 0;
  723.         for (xd = -1; xd <= 1; xd++)
  724.         for (yd = -1; yd <= 1; yd++)
  725.             if (hasmine(x+xd, y+yd)) i++;
  726.         grid[x][y] = i;
  727.     }
  728.     layed_out = 1;
  729.     if (timer_id)
  730.     XtRemoveTimeOut(timer_id);
  731.     timer_id = XtAppAddTimeOut(app, 1000L, (void_proc) timer_callback, NULL);
  732.     covered_count = gsizex*gsizey;
  733.     fix_size();
  734. }
  735.  
  736. void
  737. timer_callback()
  738. {
  739.     if (!(layed_out && game_on)) {
  740.     timer_id = 0;
  741.     return;
  742.     }
  743.     if (timer >= 999) return;
  744.     draw_digits(++timer, 1);
  745.     timer_id = XtAppAddTimeOut(app, 1000L, (void_proc) timer_callback, NULL);
  746. }
  747.  
  748. int
  749. hasmine(x, y)
  750. int x, y;
  751. {
  752.     if (x < 0 || y < 0 || x >= gsizex || y >= gsizey) return False;
  753.     return grid[x][y] == MINE;
  754. }
  755.  
  756. int
  757. is_state(x, y, state)
  758. int x, y, state;
  759. {
  760.     if (x < 0 || y < 0 || x >= gsizex || y >= gsizey) return False;
  761.     return gridview[x][y] == state;
  762. }
  763.  
  764. int
  765. iscovered(x, y)
  766. int x, y;
  767. {
  768.     if (x < 0 || y < 0 || x >= gsizex || y >= gsizey) return False;
  769.     return gridview[x][y] == COVERED;
  770. }
  771.  
  772. void
  773. uncover(x, y)
  774. int x, y;
  775. {
  776.     int dx, dy;
  777.  
  778.     if (x < 0 || y < 0 || x >= gsizex || y >= gsizey) return;
  779.     if (gridview[x][y] != COVERED) return;
  780.     gridview[x][y] = UNCOVERED;
  781.     covered_count--;
  782.     if (grid[x][y] == MINE)
  783.     boom();
  784.     else if (covered_count == mine_count)
  785.     winner();
  786.     redrawsquare(x, y);
  787.     if (grid[x][y] == 0)
  788.     for (dx = -1; dx <= 1; dx++)
  789.         for (dy = -1; dy <= 1; dy++)
  790.         uncover(x+dx, y+dy);
  791. }
  792.  
  793. void
  794. boom()
  795. {
  796.     int x, y;
  797.  
  798.     for (x = 0; x != gsizex; x++)
  799.     for (y = 0; y != gsizey; y++) {
  800.         if (grid[x][y] != MINE || gridview[x][y] == MARKED) continue;
  801.         gridview[x][y] = UNCOVERED;
  802.         redrawsquare(x, y);
  803.     }
  804.     game_on = 0;
  805.     relax_size();
  806.     set_face(FACE_DEAD);
  807. }
  808.  
  809. void
  810. winner()
  811. {
  812.     int x, y;
  813.  
  814.     game_on = 0;
  815.     relax_size();
  816.     for (x = 0; x != gsizex; x++)
  817.     for (y = 0; y != gsizey; y++)
  818.         if (gridview[x][y] == COVERED) {
  819.         gridview[x][y] = MARKED;
  820.         redrawsquare(x, y);
  821.         }
  822.     draw_digits(0, 0);
  823.     set_face(FACE_COOL);
  824.     XtAppAddTimeOut(app, 500L, (void_proc) new_best, (XtPointer) game_level);
  825. }
  826.  
  827. void
  828. restart()
  829. {
  830.     int x, y;
  831.  
  832.     for (x = 0; x != gsizex; x++)
  833.     for (y = 0; y != gsizey; y++) {
  834.         gridview[x][y] = COVERED;
  835.         grid[x][y] = 0;
  836.     }
  837.     game_on = 1;
  838.     layed_out = 0;
  839.     relax_size();
  840.     if (drawarea) {
  841.     redraw_all();
  842.     set_face(FACE_HAPPY);
  843.     }
  844.     timer = marked_count = 0;
  845. }
  846.  
  847. void
  848. clear_around(x, y)
  849. int x, y;
  850. {
  851.     int dx, dy, ct = 0;
  852.  
  853.     if (gridview[x][y] != UNCOVERED) return;
  854.     for (dx = -1; dx <= 1; dx++)
  855.     for (dy = -1; dy <= 1; dy++)
  856.         if (is_state(x+dx, y+dy, MARKED)) ct++;
  857.     if (grid[x][y] != ct) return;
  858.     for (dx = -1; dx <= 1; dx++)
  859.     for (dy = -1; dy <= 1; dy++)
  860.         if (is_state(x+dx, y+dy, COVERED)) uncover(x+dx, y+dy);
  861. }
  862.  
  863. XmString
  864. genxmstr(str)
  865. char *str;
  866. {
  867.     static XmString oldstr;
  868.  
  869.     if (oldstr) XmStringFree(oldstr);
  870.     return oldstr = XmStringLtoRCreate(str, XmSTRING_DEFAULT_CHARSET);
  871. }
  872.  
  873. void
  874. draw_hwedge(x, y, dir)
  875. int x, y, dir;
  876. {
  877.     int i;
  878.  
  879.     for (i = 0; i <= 2; i++, y += dir)
  880.     XDrawLine(disp, win, gc, x+i, y, x+DIGIT_HWEDGE_WIDTH-(i+1), y);
  881. }
  882.  
  883. void
  884. draw_midwedge(x, y)
  885. int x, y;
  886. {
  887.  
  888.     XDrawLine(disp, win, gc, x, y, x+DIGIT_HWEDGE_WIDTH-1, y);
  889.     XDrawLine(disp, win, gc, x+1, y+1, x+DIGIT_HWEDGE_WIDTH-2, y+1);
  890.     XDrawLine(disp, win, gc, x+1, y-1, x+DIGIT_HWEDGE_WIDTH-2, y-1);
  891. }
  892.  
  893. void
  894. draw_vwedge(x, y, dir)
  895. int x, y, dir;
  896. {
  897.     int i;
  898.  
  899.     for (i = 0; i <= 2; i++, x += dir)
  900.     XDrawLine(disp, win, gc, x, y+i, x, y+DIGIT_VWEDGE_HEIGHT-(i+1));
  901. }
  902.  
  903. void
  904. draw_digit(val, num, which)
  905. int val, num, which;
  906. {
  907.     int x, y;
  908.     static int segs[11] = {
  909.     127-2, 32+64, 127-(8+64),
  910.     127-(8+16), 8+32+2+64, 127-(32+16),
  911.     127-32, 1+32+64, 127,
  912.     127-16, 2
  913.     };
  914.     int seg = segs[val];
  915.  
  916.     x = !which ? DIGIT_X_OFFSET :
  917.               TOTAL_WIDTH-(DIGIT_X_OFFSET+DIGIT_COUNT*DIGIT_WIDTH);
  918.     x += num*DIGIT_WIDTH+DIGIT_MARGIN;
  919.     y = DIGIT_Y_OFFSET+DIGIT_MARGIN+1;
  920.     XSetForeground(disp, gc, cols[(seg & 1) ? COL_RED : COL_DARKRED].pixel);
  921.     draw_hwedge(x+1, y, 1);
  922.     XSetForeground(disp, gc, cols[(seg & 2) ? COL_RED : COL_DARKRED].pixel);
  923.     draw_midwedge(x+1, y+1+DIGIT_VWEDGE_HEIGHT);
  924.     XSetForeground(disp, gc, cols[(seg & 4) ? COL_RED : COL_DARKRED].pixel);
  925.     draw_hwedge(x+1, y+(1+DIGIT_VWEDGE_HEIGHT)*2, -1);
  926.     XSetForeground(disp, gc, cols[(seg & 8) ? COL_RED : COL_DARKRED].pixel);
  927.     draw_vwedge(x, y+1, 1);
  928.     XSetForeground(disp, gc, cols[(seg & 16) ? COL_RED : COL_DARKRED].pixel);
  929.     draw_vwedge(x, y+2+DIGIT_VWEDGE_HEIGHT, 1);
  930.     XSetForeground(disp, gc, cols[(seg & 32) ? COL_RED : COL_DARKRED].pixel);
  931.     draw_vwedge(x+1+DIGIT_HWEDGE_WIDTH, y+1, -1);
  932.     XSetForeground(disp, gc, cols[(seg & 64) ? COL_RED : COL_DARKRED].pixel);
  933.     draw_vwedge(x+1+DIGIT_HWEDGE_WIDTH, y+2+DIGIT_VWEDGE_HEIGHT, -1);
  934. }
  935.  
  936. void
  937. draw_digits(val, which)
  938. int val, which;
  939. {
  940.     XSetForeground(disp, gc, cols[COL_BLACK].pixel);
  941.     XFillRectangle(disp, win, gc,
  942.     !which ? DIGIT_X_OFFSET :
  943.                TOTAL_WIDTH-(DIGIT_X_OFFSET+DIGIT_COUNT*DIGIT_WIDTH),
  944.     DIGIT_Y_OFFSET,
  945.     DIGIT_WIDTH * DIGIT_COUNT, DIGIT_HEIGHT);
  946.     XSetForeground(disp, gc, cols[COL_RED].pixel);
  947.     if (val < 0) {
  948.     draw_digit(10, 0, which);
  949.     val = -val;
  950.     } else
  951.     draw_digit((val/100)%10, 0, which);
  952.     draw_digit((val/10)%10, 1, which);
  953.     draw_digit(val%10, 2, which);
  954. }
  955.  
  956. void
  957. set_level(w, level)
  958. Widget w;
  959. int level;
  960. {
  961.     int i;
  962.  
  963.     if (level == 1) {
  964.     mine_count = 10;
  965.     gsizex = gsizey = 8;
  966.     } else if (level == 2) {
  967.     mine_count = 40;
  968.     gsizex = gsizey = 16;
  969.     } else if (level == 3) {
  970.     mine_count = 99;
  971.     gsizex = 30;
  972.     gsizey = 16;
  973.     }
  974.     game_level = level-1;
  975.     if (!drawarea) return;
  976.     for (i = 0; i != XtNumber(level_buttons); i++)
  977.     if (i != level-1)
  978.         XmToggleButtonSetState(level_buttons[i], False, False);
  979.     XtVaSetValues(toplevel, XmNallowShellResize, True, NULL);
  980. /*
  981. printf("set_level: new XmNwidth=%4d, new XmNheight=%4d\n",
  982.     GSPACEX*gsizex+SIDEMARGIN*2,
  983.     GSPACEY*gsizey+TOPMARGIN+BOTMARGIN);
  984. */
  985.     XtVaSetValues(drawarea,
  986.         XmNwidth,        GSPACEX*gsizex+SIDEMARGIN*2,
  987.         XmNheight,       GSPACEY*gsizey+TOPMARGIN+BOTMARGIN,
  988.     NULL);
  989.     XtVaSetValues(toplevel, XmNallowShellResize, False, NULL);
  990.     redraw_entire();
  991.     restart();
  992. }
  993.  
  994. void
  995. tog_question()
  996. {
  997.     questions_allowed ^= 1;
  998. }
  999.  
  1000. int dialog_up;
  1001.  
  1002. void
  1003. set_custom()
  1004. {
  1005.     Widget custom, pane, w, rc, rc2, mine_w, height_w, width_w;
  1006.     char buf[20];
  1007.  
  1008.     custom = XtVaCreatePopupShell("Custom",
  1009.     topLevelShellWidgetClass, toplevel,
  1010.     XmNdeleteResponse, XmDESTROY,
  1011.     XmNdialogStyle,    XmDIALOG_FULL_APPLICATION_MODAL,
  1012.     NULL);
  1013.     pane = XtVaCreateWidget(NULL, xmPanedWindowWidgetClass, custom,
  1014.     XmNsashHeight, 1,
  1015.     XmNsashWidth,  1,
  1016.     NULL);
  1017.     rc2 = XtVaCreateManagedWidget(NULL,
  1018.     xmRowColumnWidgetClass, pane,
  1019.     NULL);
  1020.     rc = XtVaCreateManagedWidget(NULL,
  1021.     xmRowColumnWidgetClass, rc2,
  1022.     XmNorientation, XmHORIZONTAL,
  1023.     NULL);
  1024.     XtVaCreateManagedWidget("height_label",
  1025.     xmLabelGadgetClass, rc,
  1026.     NULL);
  1027.     sprintf(buf, "%d", gsizey);
  1028.     height_w = XtVaCreateManagedWidget("height_text",
  1029.     xmTextFieldWidgetClass, rc,
  1030.     XmNvalue,        buf,
  1031.     NULL);
  1032.     rc = XtVaCreateManagedWidget(NULL,
  1033.     xmRowColumnWidgetClass, rc2,
  1034.     XmNorientation, XmHORIZONTAL,
  1035.     NULL);
  1036.     XtVaCreateManagedWidget("width_label",
  1037.     xmLabelGadgetClass, rc,
  1038.     NULL);
  1039.     sprintf(buf, "%d", gsizex);
  1040.     width_w = XtVaCreateManagedWidget("width_text",
  1041.     xmTextFieldWidgetClass, rc,
  1042.     XmNvalue,        buf,
  1043.     NULL);
  1044.     rc = XtVaCreateManagedWidget(NULL,
  1045.     xmRowColumnWidgetClass, rc2,
  1046.     XmNorientation, XmHORIZONTAL,
  1047.     NULL);
  1048.     XtVaCreateManagedWidget("mines_label",
  1049.     xmLabelGadgetClass, rc,
  1050.     NULL);
  1051.     sprintf(buf, "%d", mine_count);
  1052.     mine_w = XtVaCreateManagedWidget("mines_text",
  1053.     xmTextFieldWidgetClass, rc,
  1054.     XmNvalue,        buf,
  1055.     NULL);
  1056.     rc2 = XtVaCreateManagedWidget(NULL,
  1057.     xmFormWidgetClass, pane,
  1058.     NULL);
  1059.     w = XtVaCreateManagedWidget("ok",
  1060.     xmPushButtonWidgetClass, rc2,
  1061.     XmNleftAttachment, XmATTACH_POSITION,
  1062.     XmNrightAttachment,XmATTACH_POSITION,
  1063.     XmNleftPosition,   30,
  1064.     XmNrightPosition,  70,
  1065.     NULL);
  1066.     XtAddCallback(w, XmNactivateCallback, (void_proc) dialog_ok, NULL);
  1067.     XtManageChild(pane);
  1068.     XtPopup(custom, XtGrabExclusive);
  1069.     dialog_up = True;
  1070.     while (dialog_up) {
  1071.     XtAppProcessEvent(app, XtIMAll);
  1072.     XSync(disp, 0);
  1073.     }
  1074.     XtPopdown(custom);
  1075.     get_text_int(width_w, &gsizex);
  1076.     if (gsizex > 100) gsizex = 100;
  1077.     if (gsizex < 8) gsizex = 8;
  1078.     get_text_int(height_w, &gsizey);
  1079.     if (gsizey > 100) gsizey = 100;
  1080.     if (gsizey < 8) gsizey = 8;
  1081.     get_text_int(mine_w, &mine_count);
  1082.     if (mine_count < 1) mine_count = 1;
  1083.     set_level((Widget) 0, 4);
  1084. }
  1085.  
  1086. void
  1087. dialog_ok()
  1088. {
  1089.     dialog_up = False;
  1090. }
  1091.  
  1092. void
  1093. get_text_int(w, val)
  1094. Widget w;
  1095. int *val;
  1096. {
  1097.     char *str;
  1098.  
  1099.     str = XmTextFieldGetString(w);
  1100.     if (!str) return;
  1101.     if (atoi(str)) *val = atoi(str);
  1102.     XtFree(str);
  1103. }
  1104.  
  1105. void
  1106. best_times()
  1107. {
  1108.     Widget custom, pane, w, rc2, ok_w;
  1109.     Widget matrix[9];
  1110.     char buf[20];
  1111.     struct scores *sc;
  1112.  
  1113.     sc = get_scores();
  1114.     custom = XtVaCreatePopupShell("Best",
  1115.     topLevelShellWidgetClass, toplevel,
  1116.     XmNdeleteResponse, XmDESTROY,
  1117.     XmNdialogStyle,    XmDIALOG_FULL_APPLICATION_MODAL,
  1118.     NULL);
  1119.     pane = XtVaCreateWidget(NULL, xmPanedWindowWidgetClass, custom,
  1120.     XmNsashHeight, 1,
  1121.     XmNsashWidth,  1,
  1122.     NULL);
  1123.     XtVaCreateManagedWidget("label",
  1124.     xmLabelGadgetClass, pane,
  1125.     NULL);
  1126.     rc2 = XtVaCreateManagedWidget(NULL,
  1127.     xmFormWidgetClass, pane,
  1128.     NULL);
  1129.     matrix[0] = XtVaCreateManagedWidget("begin_label",
  1130.     xmLabelGadgetClass, rc2,
  1131.     XmNtopAttachment, XmATTACH_FORM,
  1132.     XmNleftAttachment, XmATTACH_FORM,
  1133.     NULL);
  1134.     sprintf(buf, "%d", sc->times[0]);
  1135.     matrix[1] = XtVaCreateManagedWidget("begin_time",
  1136.     xmLabelGadgetClass, rc2,
  1137.     XmNtopAttachment,   XmATTACH_FORM,
  1138.     XmNleftAttachment,  XmATTACH_OPPOSITE_WIDGET,
  1139.     XmNlabelString,        genxmstr(buf),
  1140.     XmNalignment,       XmALIGNMENT_BEGINNING,
  1141.     NULL);
  1142.     matrix[2] = XtVaCreateManagedWidget("begin_name",
  1143.     xmLabelGadgetClass, rc2,
  1144.     XmNtopAttachment,   XmATTACH_FORM,
  1145.     XmNleftAttachment,  XmATTACH_WIDGET,
  1146.     XmNleftWidget,        matrix[1],
  1147.     XmNrightAttachment, XmATTACH_FORM,
  1148.     XmNlabelString,        genxmstr(sc->names[0]),
  1149.     XmNleftOffset,        20,
  1150.     XmNalignment,       XmALIGNMENT_BEGINNING,
  1151.     NULL);
  1152.     matrix[3] = XtVaCreateManagedWidget("inter_label",
  1153.     xmLabelGadgetClass, rc2,
  1154.     XmNtopAttachment,   XmATTACH_WIDGET,
  1155.     XmNtopWidget,        matrix[0],
  1156.     XmNleftAttachment,  XmATTACH_FORM,
  1157.     NULL);
  1158.     sprintf(buf, "%d", sc->times[1]);
  1159.     matrix[4] = XtVaCreateManagedWidget("inter_time",
  1160.     xmLabelGadgetClass, rc2,
  1161.     XmNtopAttachment,   XmATTACH_WIDGET,
  1162.     XmNtopWidget,        matrix[0],
  1163.     XmNleftAttachment,  XmATTACH_WIDGET,
  1164.     XmNleftWidget,        matrix[3],
  1165.     XmNleftOffset,        20,
  1166.     XmNlabelString,        genxmstr(buf),
  1167.     XmNalignment,       XmALIGNMENT_BEGINNING,
  1168.     NULL);
  1169.     XtVaSetValues(matrix[1], XmNleftWidget, matrix[4], NULL);
  1170.     matrix[5] = XtVaCreateManagedWidget("inter_name",
  1171.     xmLabelGadgetClass, rc2,
  1172.     XmNtopAttachment,   XmATTACH_WIDGET,
  1173.     XmNtopWidget,        matrix[2],
  1174.     XmNleftAttachment,  XmATTACH_OPPOSITE_WIDGET,
  1175.     XmNleftWidget,        matrix[2],
  1176.     XmNrightAttachment, XmATTACH_FORM,
  1177.     XmNlabelString,        genxmstr(sc->names[1]),
  1178.     XmNalignment,       XmALIGNMENT_BEGINNING,
  1179.     NULL);
  1180.     matrix[6] = XtVaCreateManagedWidget("expert_label",
  1181.     xmLabelGadgetClass, rc2,
  1182.     XmNtopAttachment,   XmATTACH_WIDGET,
  1183.     XmNtopWidget,        matrix[3],
  1184.     XmNleftAttachment,  XmATTACH_FORM,
  1185.     XmNbottomAttachment,XmATTACH_FORM,
  1186.     NULL);
  1187.     sprintf(buf, "%d", sc->times[2]);
  1188.     matrix[7] = XtVaCreateManagedWidget("expert_time",
  1189.     xmLabelGadgetClass, rc2,
  1190.     XmNtopAttachment,   XmATTACH_WIDGET,
  1191.     XmNtopWidget,        matrix[4],
  1192.     XmNleftAttachment,  XmATTACH_OPPOSITE_WIDGET,
  1193.     XmNleftWidget,        matrix[4],
  1194.     XmNbottomAttachment,XmATTACH_FORM,
  1195.     XmNlabelString,        genxmstr(buf),
  1196.     XmNalignment,       XmALIGNMENT_BEGINNING,
  1197.     NULL);
  1198.     matrix[8] = XtVaCreateManagedWidget("expert_name",
  1199.     xmLabelGadgetClass, rc2,
  1200.     XmNtopAttachment,   XmATTACH_WIDGET,
  1201.     XmNtopWidget,        matrix[5],
  1202.     XmNleftAttachment,  XmATTACH_OPPOSITE_WIDGET,
  1203.     XmNleftWidget,        matrix[5],
  1204.     XmNrightAttachment, XmATTACH_FORM,
  1205.     XmNbottomAttachment,XmATTACH_FORM,
  1206.     XmNlabelString,        genxmstr(sc->names[2]),
  1207.     XmNalignment,       XmALIGNMENT_BEGINNING,
  1208.     NULL);
  1209.     rc2 = XtVaCreateManagedWidget(NULL,
  1210.     xmFormWidgetClass, pane,
  1211.     NULL);
  1212.     ok_w = XtVaCreateManagedWidget("ok",
  1213.     xmPushButtonWidgetClass, rc2,
  1214.     XmNleftAttachment, XmATTACH_POSITION,
  1215.     XmNrightAttachment,XmATTACH_POSITION,
  1216.     XmNleftPosition,   0,
  1217.     XmNrightPosition,  50,
  1218.     NULL);
  1219.     XtAddCallback(ok_w, XmNactivateCallback, (void_proc) dialog_ok, NULL);
  1220.     w = XtVaCreateManagedWidget("clear",
  1221.     xmPushButtonWidgetClass, rc2,
  1222.     XmNleftAttachment, XmATTACH_POSITION,
  1223.     XmNrightAttachment,XmATTACH_POSITION,
  1224.     XmNleftPosition,   50,
  1225.     XmNrightPosition,  100,
  1226.     NULL);
  1227.     XtAddCallback(w, XmNactivateCallback, (void_proc) clear_scores, NULL);
  1228.     if (cant_write_score_file()) XtSetSensitive(w, False);
  1229.     XtManageChild(pane);
  1230.     XtPopup(custom, XtGrabExclusive);
  1231.     XmProcessTraversal(ok_w, XmTRAVERSE_CURRENT);
  1232.     dialog_up = True;
  1233.     while (dialog_up) {
  1234.     XtAppProcessEvent(app, XtIMAll);
  1235.     XSync(disp, 0);
  1236.     }
  1237.     XtPopdown(custom);
  1238.  
  1239. }
  1240.  
  1241. void
  1242. about()
  1243. {
  1244.     Widget custom, pane, w, rc2;
  1245.     char buf[100];
  1246.  
  1247.     custom = XtVaCreatePopupShell("About",
  1248.     topLevelShellWidgetClass, toplevel,
  1249.     XmNdeleteResponse, XmDESTROY,
  1250.     XmNdialogStyle,    XmDIALOG_FULL_APPLICATION_MODAL,
  1251.     NULL);
  1252.     pane = XtVaCreateWidget(NULL, xmPanedWindowWidgetClass, custom,
  1253.     XmNsashHeight, 1,
  1254.     XmNsashWidth,  1,
  1255.     NULL);
  1256.     sprintf(buf, "xmine 1.0.%d by Paul Falstad", PATCHLEVEL);
  1257.     XtVaCreateManagedWidget("label",
  1258.     xmLabelGadgetClass, pane,
  1259.     XmNlabelString,     genxmstr(buf),
  1260.     NULL);
  1261.     rc2 = XtVaCreateManagedWidget(NULL,
  1262.     xmFormWidgetClass, pane,
  1263.     NULL);
  1264.     w = XtVaCreateManagedWidget("ok",
  1265.     xmPushButtonWidgetClass, rc2,
  1266.     XmNleftAttachment, XmATTACH_POSITION,
  1267.     XmNrightAttachment,XmATTACH_POSITION,
  1268.     XmNleftPosition,   30,
  1269.     XmNrightPosition,  70,
  1270.     NULL);
  1271.     XtAddCallback(w, XmNactivateCallback, (void_proc) dialog_ok, NULL);
  1272.     XtManageChild(pane);
  1273.     XtPopup(custom, XtGrabExclusive);
  1274.     XmProcessTraversal(w, XmTRAVERSE_CURRENT);
  1275.     dialog_up = True;
  1276.     while (dialog_up) {
  1277.     XtAppProcessEvent(app, XtIMAll);
  1278.     XSync(disp, 0);
  1279.     }
  1280.     XtPopdown(custom);
  1281. }
  1282.  
  1283. void
  1284. get_score_file_name(buf)
  1285. char *buf;
  1286. {
  1287.     if (*SCORE_FILE == '~' && getenv("HOME"))
  1288.     sprintf(buf, "%s%s", getenv("HOME"), SCORE_FILE+1);
  1289.     else
  1290.     strcpy(buf, SCORE_FILE);
  1291. }
  1292.  
  1293. struct scores *
  1294. get_scores()
  1295. {
  1296.     static struct scores sc;
  1297.     char buf[1000];
  1298.     int i, score;
  1299.     FILE *in;
  1300.  
  1301.     for (i = 0; i != 3; i++) {
  1302.     strcpy(sc.names[i], "Anonymous");
  1303.     sc.times[i] = 999;
  1304.     }
  1305.     get_score_file_name(buf);
  1306.     if (in = fopen(buf, "r")) {
  1307.     while (fscanf(in, "%d %d \"%[^\"]\"", &i, &score, buf) == 3) {
  1308.         if (i < 0 || i > 2) break;
  1309.         strcpy(sc.names[i], buf);
  1310.         sc.times[i] = score;
  1311.     }
  1312.     fclose(in);
  1313.     }
  1314.     return ≻
  1315. }
  1316.  
  1317. void
  1318. write_scores(sc)
  1319. struct scores *sc;
  1320. {
  1321.     int i;
  1322.     char buf[1000];
  1323.     FILE *out;
  1324.  
  1325.     get_score_file_name(buf);
  1326.     if (!(out = fopen(buf, "w")))
  1327.     return;
  1328.     for (i = 0; i != 3; i++)
  1329.     if (sc->times[i] != 999)
  1330.         fprintf(out, "%d %d \"%s\"\n", i, sc->times[i], sc->names[i]);
  1331.     fclose(out);
  1332. }
  1333.  
  1334. void
  1335. new_best(level)
  1336. int level;
  1337. {
  1338.     Widget custom, pane, rc2, name_w, w;
  1339.     char *str;
  1340.     struct scores *sc;
  1341.  
  1342.     if (level < 0 || level >= 3) return;
  1343.     sc = get_scores();
  1344.     if (timer >= sc->times[level]) return;
  1345.     custom = XtVaCreatePopupShell("HighScorer",
  1346.     topLevelShellWidgetClass, toplevel,
  1347.     XmNdeleteResponse, XmDESTROY,
  1348.     XmNdialogStyle,    XmDIALOG_FULL_APPLICATION_MODAL,
  1349.     NULL);
  1350.     pane = XtVaCreateWidget(NULL, xmPanedWindowWidgetClass, custom,
  1351.     XmNsashHeight, 1,
  1352.     XmNsashWidth,  1,
  1353.     NULL);
  1354.     XtVaCreateManagedWidget("label",
  1355.     xmLabelGadgetClass, pane,
  1356.     NULL);
  1357.     name_w = XtVaCreateManagedWidget("name",
  1358.     xmTextFieldWidgetClass, pane, NULL);
  1359.     XtAddCallback(name_w, XmNactivateCallback, (void_proc) dialog_ok, NULL);
  1360.     rc2 = XtVaCreateManagedWidget(NULL,
  1361.     xmFormWidgetClass, pane,
  1362.     NULL);
  1363.     w = XtVaCreateManagedWidget("ok",
  1364.     xmPushButtonWidgetClass, rc2,
  1365.     XmNleftAttachment, XmATTACH_POSITION,
  1366.     XmNrightAttachment,XmATTACH_POSITION,
  1367.     XmNleftPosition,   30,
  1368.     XmNrightPosition,  70,
  1369.     NULL);
  1370.     XtAddCallback(w, XmNactivateCallback, (void_proc) dialog_ok, NULL);
  1371.     XtManageChild(pane);
  1372.     XtPopup(custom, XtGrabExclusive);
  1373.     XmTextFieldSetSelection(name_w, 0, XmTextFieldGetLastPosition(name_w),
  1374. CurrentTime);
  1375.     XmProcessTraversal(name_w, XmTRAVERSE_CURRENT);
  1376.     dialog_up = True;
  1377.     while (dialog_up) {
  1378.     XtAppProcessEvent(app, XtIMAll);
  1379.     XSync(disp, 0);
  1380.     }
  1381.     XtPopdown(custom);
  1382.     str = XmTextFieldGetString(name_w);
  1383.     if (str && *str) {
  1384.     strcpy(sc->names[level], str);
  1385.     sc->times[level] = timer;
  1386.     write_scores(sc);
  1387.     }
  1388.     if (str) XtFree(str);
  1389.     best_times();
  1390. }
  1391.  
  1392. void
  1393. clear_scores()
  1394. {
  1395.     char buf[1000];
  1396.     FILE *out;
  1397.  
  1398.     dialog_up = False;
  1399.     get_score_file_name(buf);
  1400.     if (out = fopen(buf, "w")) fclose(out);
  1401. }
  1402.  
  1403. int
  1404. cant_write_score_file()
  1405. {
  1406.     return geteuid() != getuid();
  1407. }
  1408.  
  1409. void
  1410. fix_size()
  1411. {
  1412.     XSizeHints hints;
  1413.     Dimension wid, hgt;
  1414.  
  1415.     XtVaGetValues(toplevel,
  1416.     XmNwidth, &wid,
  1417.     XmNheight, &hgt,
  1418.     NULL);
  1419.     hints.flags = PMaxSize|PMinSize;
  1420.     hints.max_width = hints.min_width = wid;
  1421.     hints.max_height = hints.min_height = hgt;
  1422.     XSetWMNormalHints(disp, XtWindow(toplevel), &hints);
  1423. }
  1424.  
  1425. void
  1426. relax_size()
  1427. {
  1428.     XSizeHints hints;
  1429.     Dimension wid, hgt, menu_hgt;
  1430.  
  1431.     XtVaGetValues(toplevel,
  1432.     XmNwidth, &wid,
  1433.     XmNheight, &hgt,
  1434.     NULL);
  1435.     hints.flags = PMaxSize|PMinSize|PResizeInc;
  1436.     XtVaGetValues(menubar,
  1437.     XmNheight, &menu_hgt,
  1438.     NULL);
  1439.     hints.min_width = SIDEMARGIN*2+GSPACEX*INITIAL_SIZE_X;
  1440.     hints.min_height = TOPMARGIN+BOTMARGIN+menu_hgt+GSPACEY*INITIAL_SIZE_Y;
  1441.     hints.max_width = hints.max_height = 10000;
  1442.     hints.width_inc = GSPACEX;
  1443.     hints.height_inc = GSPACEY;
  1444.     XSetWMNormalHints(disp, XtWindow(toplevel), &hints);
  1445. }
  1446.  
  1447. void
  1448. resize_handler(w, data, event, contflag)
  1449. Widget w;
  1450. XtPointer data;
  1451. XEvent *event;
  1452. Boolean *contflag;
  1453. {
  1454.     int new_gsizex, new_gsizey;
  1455.     static int started = 0;
  1456.  
  1457.     if (!started) {
  1458.     started = 1;
  1459.     relax_size();
  1460.     }
  1461.     if (event->type != ConfigureNotify) return;
  1462.     if (layed_out && game_on) return;
  1463.  
  1464. /*
  1465. printf(
  1466.   "resize_handler: event->xconfigure.width=%4d, event.xconfigure.height=%4d\n",
  1467.     event->xconfigure.width,
  1468.     event->xconfigure.height);
  1469. */
  1470.     new_gsizex = (event->xconfigure.width-SIDEMARGIN*2 + (GSPACEX-1)) / GSPACEX;
  1471.     new_gsizey = (event->xconfigure.height-
  1472.               (TOPMARGIN+BOTMARGIN) + (GSPACEY-1)) / GSPACEY;
  1473. /*
  1474. printf(
  1475.    "resize_handler: gsizex=%2d, new_gsizex=%2d;  gsizey=%2d, new_gsizey=%2d\n",
  1476.    gsizex, new_gsizex, gsizey, new_gsizey);
  1477. */
  1478.     if (new_gsizex > MAX_GSIZEX)
  1479.     new_gsizex = MAX_GSIZEX;
  1480.     if (new_gsizey > MAX_GSIZEY)
  1481.     new_gsizey = MAX_GSIZEY;
  1482.     if (new_gsizex != gsizex || new_gsizey != gsizey) {
  1483.     gsizex = new_gsizex;
  1484.     gsizey = new_gsizey;
  1485.     set_level(w, 4);
  1486.     }
  1487. }
  1488.